<?php

namespace app\common\utils;

use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;

/**
 * 日志服务类,使用 monolog扩展: composer require monolog/monolog
 */
class MyLog
{
    /**
     * @var Logger $logger
     */
    private static $logger;

    private static $log_data;

    /**
     * record
     * @param string $log_file_name
     * @param null $handler_name
     * @throws
     */
    public static function record($log_file_name = '', $handler_name = null)
    {
        if (empty($log_file_name)) {
            $log_file_name = Init::$log_suffix;
        }
        if (empty($handler_name)) {
            $handler_name = $log_file_name;
        }

        //模块名称
        $module_name = app('http')->getName() ?? 'default';

        //日志路径
        $log_path = env("LOG_PATH") ?? config('app.my_log_path');
        $log_file_path = $log_path . '/' . date('Y/m/') . date('Ymd') . '_' . $module_name . '_' . $log_file_name . '.log';
        if (!file_exists($log_file_path)) {
            self::_createFolder($log_file_path);
        }

        $stream_handler = new StreamHandler($log_file_path, Logger::INFO);
        $dateFormat = '';
        $url = @$_SERVER['REQUEST_URI'] ?: '';
        $ip = MyTools::getRealIP();
        $microtime = microtime(true);
        $now = date('Y-m-d H:i:s') . substr(microtime(), 1, 4);
        $log_sort = Init::$log_sort++;

        //程序流转追踪
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $backtrace_file = @explode('/', $backtrace[0]['file']);
        $backtrace_file = @$backtrace_file[count($backtrace_file) - 3] . '/' . @$backtrace_file[count($backtrace_file) - 1];
        $back_simple = @$backtrace_file . ':' . @$backtrace[0]['line'] . '->' . @$backtrace[1]['function'];

        //日志输出为json格式
        $output = '{"time":"' . $now . '","channel":"%channel%","level":"%level_name%","url":"' . $url . '","ip":"' . $ip . '","message":"%message%","reqId":"' . Init::$request_id . '","sort":"' . $log_sort . '","microtime":"' . $microtime . '","backtrace":"' . $back_simple . '","context":%context%}' . "\n";

        $formatter = new LineFormatter($output, $dateFormat);
        $stream_handler->setFormatter($formatter);

        $logger = new Logger($handler_name);
        $logger->pushHandler($stream_handler);

        self::$logger = $logger;
        return new self();
    }

    public function info($context = null, $message = '')
    {
        self::$logger->info($message, self::_format($context));
    }

    public function warning($context = null, $message = '')
    {
        self::$logger->warning($message, self::_format($context));
    }

    public function notice($context = null, $message = '')
    {
        self::$logger->notice($message, self::_format($context));
    }

    public function error($context = null, $message = '')
    {
        self::$logger->error($message, self::_format($context));
    }

    public function debug($context = null, $message = '')
    {
        self::$logger->debug($message, self::_format($context));
    }

    /**
     * 格式化日志内容，统一转为数组
     */
    private static function _format($context = null)
    {
        //array
        if (is_array($context)) {
            return $context;
        }

        //json
        $arr = @json_decode($context, true);
        if (is_array($arr)) {
            return $arr;
        }

        //string
        return ['data' => $context];
    }

    /**
     * Exception信息 转化为数组
     * @param \Exception|\Error $e
     * @return array
     */
    public static function getTraceAsArray($e)
    {
        $string = 'Code:' . @$e->getCode() . "\n" . @$e->getMessage() . "\n" . @$e->getTraceAsString();
        $array = explode("\n", $string) ?: [];

        //转换为关联数组，方便json查看
        $result = [];
        foreach ($array as $k => $v) {
            $result['k' . $k] = $v;
        }
        return $result;
    }

    public static function writeExceptionLog($e, $message = 'exception')
    {
        self::record()->error(self::getTraceAsArray($e), $message);
    }

    public static function printExceptionLogAndExit($e)
    {
        PE(self::getTraceAsArray($e));
    }

    private static function _createFolder($file)
    {
        $dir = dirname($file);
        if (!is_dir($dir)) {
            @mkdir($dir, 0777, true);
            @chmod($dir, 0777);
        }
        if (!is_dir($dir)) {
            @exec("mkdir -p {$dir}");
            @exec("chmod -R 777 {$dir}");
        }
        if (!file_exists($file)) {
            @exec("touch {$file}");
            @exec("chmod 777 {$file}");
        }
    }

}